// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
#define BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_

#include <dispatch/dispatch.h>

#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"

namespace base {
namespace mac {

    // This is an implementation of the TaskRunner interface that runs closures on
    // a thread managed by Apple's libdispatch. This has the benefit of being able
    // to PostTask() and friends to a dispatch queue, while being reusable as a
    // dispatch_queue_t.
    //
    // One would use this class if an object lives exclusively on one thread but
    // needs a dispatch_queue_t for use in a system API. This ensures all dispatch
    // callbacks happen on the same thread as Closure tasks.
    //
    // A LibDispatchTaskRunner will continue to run until all references to the
    // underlying dispatch queue are released.
    //
    // Important Notes:
    //   - There is no MessageLoop running on this thread, and ::current() returns
    //     NULL.
    //   - No nested loops can be run, and all tasks are run non-nested.
    //   - Work scheduled via libdispatch runs at the same priority as and is
    //     interleaved with posted tasks, though FIFO order is guaranteed.
    //
    class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
    public:
        // Starts a new serial dispatch queue with a given name.
        explicit LibDispatchTaskRunner(const char* name);

        // base::TaskRunner:
        bool PostDelayedTask(const tracked_objects::Location& from_here,
            const Closure& task,
            base::TimeDelta delay) override;
        bool RunsTasksOnCurrentThread() const override;

        // base::SequencedTaskRunner:
        bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
            const Closure& task,
            base::TimeDelta delay) override;

        // This blocks the calling thread until all work on the dispatch queue has
        // been run and the queue has been destroyed. Destroying a queue requires
        // ALL retained references to it to be released. Any new tasks posted to
        // this thread after shutdown are dropped.
        void Shutdown();

        // Returns the dispatch queue associated with this task runner, for use with
        // system APIs that take dispatch queues. The caller is responsible for
        // retaining the result.
        //
        // All properties (context, finalizer, etc.) are managed by this class, and
        // clients should only use the result of this for dispatch_async().
        dispatch_queue_t GetDispatchQueue() const;

    protected:
        ~LibDispatchTaskRunner() override;

    private:
        static void Finalizer(void* context);

        dispatch_queue_t queue_;

        // The event on which Shutdown waits until Finalizer runs.
        base::WaitableEvent queue_finalized_;
    };

} // namespace mac
} // namespace base

#endif // BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
